@@ -1,2 +1,15 @@ |
||
| 1 | 1 |
.scenario-import {
|
| 2 |
+ .agent-import-list {
|
|
| 3 |
+ .agent-import {
|
|
| 4 |
+ margin-bottom: 20px; |
|
| 5 |
+ |
|
| 6 |
+ .instructions {
|
|
| 7 |
+ margin-bottom: 10px; |
|
| 8 |
+ } |
|
| 9 |
+ |
|
| 10 |
+ .current {
|
|
| 11 |
+ font-weight: bold; |
|
| 12 |
+ } |
|
| 13 |
+ } |
|
| 14 |
+ } |
|
| 2 | 15 |
} |
@@ -19,13 +19,13 @@ module Agents |
||
| 19 | 19 |
Your event can provide any of the following optional parameters or you can provide defaults: |
| 20 | 20 |
|
| 21 | 21 |
* `device` - your user's device name to send the message directly to that device, rather than all of the user's devices |
| 22 |
- * `title` or `subject` - your notifications's title |
|
| 22 |
+ * `title` or `subject` - your notification's title |
|
| 23 | 23 |
* `url` - a supplementary URL to show with your message - `512` Character Limit |
| 24 | 24 |
* `url_title` - a title for your supplementary URL, otherwise just the URL is shown - `100` Character Limit |
| 25 | 25 |
* `priority` - send as `-1` to always send as a quiet notification, `0` is default, `1` to display as high-priority and bypass the user's quiet hours, or `2` for emergency priority: [Please read Pushover Docs on Emergency Priority](https://pushover.net/api#priority) |
| 26 | 26 |
* `sound` - the name of one of the sounds supported by device clients to override the user's default sound choice. [See PushOver docs for sound options.](https://pushover.net/api#sounds) |
| 27 |
- * `retry` - Requred for emergency priority - Specifies how often (in seconds) the Pushover servers will send the same notification to the user. Minimum value: `30` |
|
| 28 |
- * `expire` - Requred for emergency priority - Specifies how many seconds your notification will continue to be retried for (every retry seconds). Maximum value: `86400` |
|
| 27 |
+ * `retry` - Required for emergency priority - Specifies how often (in seconds) the Pushover servers will send the same notification to the user. Minimum value: `30` |
|
| 28 |
+ * `expire` - Required for emergency priority - Specifies how many seconds your notification will continue to be retried for (every retry seconds). Maximum value: `86400` |
|
| 29 | 29 |
|
| 30 | 30 |
Your event can also pass along a timestamp parameter: |
| 31 | 31 |
|
@@ -42,10 +42,10 @@ module Agents |
||
| 42 | 42 |
'title' => '', |
| 43 | 43 |
'url' => '', |
| 44 | 44 |
'url_title' => '', |
| 45 |
- 'priority' => 0, |
|
| 45 |
+ 'priority' => '0', |
|
| 46 | 46 |
'sound' => 'pushover', |
| 47 |
- 'retry' => 0, |
|
| 48 |
- 'expire' => 0, |
|
| 47 |
+ 'retry' => '0', |
|
| 48 |
+ 'expire' => '0', |
|
| 49 | 49 |
'expected_receive_period_in_days' => '1' |
| 50 | 50 |
} |
| 51 | 51 |
end |
@@ -102,6 +102,5 @@ module Agents |
||
| 102 | 102 |
response = HTTParty.post(API_URL, :query => post_params) |
| 103 | 103 |
puts response |
| 104 | 104 |
end |
| 105 |
- |
|
| 106 | 105 |
end |
| 107 | 106 |
end |
@@ -77,7 +77,7 @@ |
||
| 77 | 77 |
<div class="col-md-12"> |
| 78 | 78 |
<div class="form-group"> |
| 79 | 79 |
<%= f.label :options %> |
| 80 |
- <textarea rows="10" id="agent_options" name="agent[options]" class="form-control live-json-editor <%= (@agent.new_record? && @agent.options == {}) ? "showing-default" : "" %>">
|
|
| 80 |
+ <textarea rows="15" id="agent_options" name="agent[options]" class="form-control live-json-editor <%= (@agent.new_record? && @agent.options == {}) ? "showing-default" : "" %>">
|
|
| 81 | 81 |
<%= Utils.jsonify((@agent.new_record? && @agent.options == {}) ? @agent.default_options : @agent.options) %>
|
| 82 | 82 |
</textarea> |
| 83 | 83 |
</div> |
@@ -104,7 +104,7 @@ |
||
| 104 | 104 |
|
| 105 | 105 |
<div class='row'> |
| 106 | 106 |
<div class="col-md-12"> |
| 107 |
- <%= f.submit :class => "btn btn-primary" %> |
|
| 107 |
+ <%= f.submit "Save", :class => "btn btn-primary" %> |
|
| 108 | 108 |
</div> |
| 109 | 109 |
</div> |
| 110 | 110 |
|
@@ -31,18 +31,22 @@ |
||
| 31 | 31 |
|
| 32 | 32 |
<script> |
| 33 | 33 |
var agentPaths = {};
|
| 34 |
- <% if current_user -%> |
|
| 35 |
- var myAgents = <%= Utils.jsonify(current_user.agents.select([:name, :id, :schedule]).inject({}) {|m, a| m[a.name] = agent_path(a); m }) %>;
|
|
| 34 |
+ var agentNames = []; |
|
| 35 |
+ <% if current_user.present? -%> |
|
| 36 |
+ var myAgents = <%= Utils.jsonify(current_user.agents.pluck(:name, :id).inject({}) {|m, a| m[a.first] = agent_path(a.last); m }) %>;
|
|
| 37 |
+ var myScenarios = <%= Utils.jsonify(current_user.scenarios.pluck(:name, :id).inject({}) {|m, s| m[s.first + " Scenario"] = scenario_path(s.last); m }) %>;
|
|
| 36 | 38 |
$.extend(agentPaths, myAgents); |
| 39 |
+ $.extend(agentPaths, myScenarios); |
|
| 40 |
+ agentPaths["All Agents Index"] = <%= Utils.jsonify agents_path %>; |
|
| 41 |
+ agentPaths["New Agent"] = <%= Utils.jsonify new_agent_path %>; |
|
| 42 |
+ agentPaths["Account"] = <%= Utils.jsonify edit_user_registration_path %>; |
|
| 43 |
+ agentPaths["Events Index"] = <%= Utils.jsonify events_path %>; |
|
| 44 |
+ agentPaths["View Agent Diagram"] = <%= Utils.jsonify diagram_agents_path %>; |
|
| 45 |
+ agentPaths["Run Event Propagation"] = { url: <%= Utils.jsonify propagate_agents_path %>, method: 'POST' };
|
|
| 46 |
+ |
|
| 47 |
+ |
|
| 48 |
+ $.each(agentPaths, function(name, v) { agentNames.push(name); });
|
|
| 37 | 49 |
<% end -%> |
| 38 |
- agentPaths["All Agents Index"] = <%= Utils.jsonify agents_path %>; |
|
| 39 |
- agentPaths["New Agent"] = <%= Utils.jsonify new_agent_path %>; |
|
| 40 |
- agentPaths["Account"] = <%= Utils.jsonify edit_user_registration_path %>; |
|
| 41 |
- agentPaths["Events Index"] = <%= Utils.jsonify events_path %>; |
|
| 42 |
- agentPaths["View Agent Diagram"] = <%= Utils.jsonify diagram_agents_path %>; |
|
| 43 |
- agentPaths["Run Event Propagation"] = { url: <%= Utils.jsonify propagate_agents_path %>, method: 'POST' };
|
|
| 44 |
- var agentNames = []; |
|
| 45 |
- $.each(agentPaths, function(name, v) { agentNames.push(name); });
|
|
| 46 | 50 |
</script> |
| 47 | 51 |
</body> |
| 48 | 52 |
</html> |
@@ -7,10 +7,9 @@ |
||
| 7 | 7 |
</div> |
| 8 | 8 |
|
| 9 | 9 |
<div class='row'> |
| 10 |
- <blockquote> |
|
| 11 |
- You can import Scenarios, either from a <code>.json</code> file, or via a public Scenario URL. When you |
|
| 12 |
- import a Scenario, Huginn will keep track of where it came from and later let you update it. |
|
| 13 |
- </blockquote> |
|
| 10 |
+ <blockquote>You can import Scenarios, either from a <code>.json</code> file, or via a public |
|
| 11 |
+ Scenario URL. When you import a Scenario, Huginn will keep track of where it came from and |
|
| 12 |
+ later let you update it.</blockquote> |
|
| 14 | 13 |
</div> |
| 15 | 14 |
|
| 16 | 15 |
<div class='row'> |
@@ -22,8 +22,10 @@ |
||
| 22 | 22 |
<div class="page-header"> |
| 23 | 23 |
<h2> |
| 24 | 24 |
<%= @scenario_import.parsed_data["name"] %> |
| 25 |
- <span class='text-muted'>(<%= pluralize @scenario_import.parsed_data["agents"].length, "Agent" %> |
|
| 26 |
- ; exported <%= time_ago_in_words Time.parse(@scenario_import.parsed_data["exported_at"]) %> ago)</span> |
|
| 25 |
+ <span class='text-muted'> |
|
| 26 |
+ (<%= pluralize @scenario_import.parsed_data["agents"].length, "Agent" %>; |
|
| 27 |
+ exported <%= time_ago_in_words Time.parse(@scenario_import.parsed_data["exported_at"]) %> ago) |
|
| 28 |
+ </span> |
|
| 27 | 29 |
</h2> |
| 28 | 30 |
</div> |
| 29 | 31 |
|
@@ -48,7 +50,7 @@ |
||
| 48 | 50 |
</h3> |
| 49 | 51 |
|
| 50 | 52 |
<% if agent_diff.agent_exists? %> |
| 51 |
- <div> |
|
| 53 |
+ <div class="instructions"> |
|
| 52 | 54 |
This Agent exists in your Huginn system. |
| 53 | 55 |
|
| 54 | 56 |
<% if agent_diff.requires_merge? %> |
@@ -105,7 +107,7 @@ |
||
| 105 | 107 |
</div> |
| 106 | 108 |
|
| 107 | 109 |
<div class='col-md-6'> |
| 108 |
- <textarea name="scenario_import[merges][<%= index %>][options]" rows='10' class="form-control live-json-editor"> |
|
| 110 |
+ <textarea name="scenario_import[merges][<%= index %>][options]" rows='15' class="form-control live-json-editor"> |
|
| 109 | 111 |
<%= Utils.pretty_jsonify(agent_diff.options.updated) %> |
| 110 | 112 |
</textarea> |
| 111 | 113 |
</div> |
@@ -7,7 +7,8 @@ |
||
| 7 | 7 |
</h2> |
| 8 | 8 |
</div> |
| 9 | 9 |
|
| 10 |
- <blockquote>Scenarios are named groups of Agents. Scenarios allow you to organize your agents, and to export sets of Agents for sharing.</blockquote> |
|
| 10 |
+ <blockquote>Scenarios are named groups of Agents. Scenarios allow you to organize your agents, |
|
| 11 |
+ and to import and export sets of Agents to share.</blockquote> |
|
| 11 | 12 |
|
| 12 | 13 |
<table class='table table-striped'> |
| 13 | 14 |
<tr> |
@@ -2,7 +2,7 @@ |
||
| 2 | 2 |
<div class='row'> |
| 3 | 3 |
<div class='col-md-12'> |
| 4 | 4 |
<div class="page-header"> |
| 5 |
- <h2><%= "Public" if @scenario.public? %> Scenario <span class='label label-info scenario'><%= @scenario.name %></span></h2> |
|
| 5 |
+ <h2><span class='label label-info scenario'><%= @scenario.name %></span> <%= "Public" if @scenario.public? %> Scenario</h2> |
|
| 6 | 6 |
</div> |
| 7 | 7 |
|
| 8 | 8 |
<% if @scenario.description.present? %> |
@@ -1,5 +1,5 @@ |
||
| 1 | 1 |
/* |
| 2 |
- Copyright (c) 2013, Andrew Cantino |
|
| 2 |
+ Copyright (c) 2014, Andrew Cantino |
|
| 3 | 3 |
Copyright (c) 2009, Andrew Cantino & Kyle Maxwell |
| 4 | 4 |
|
| 5 | 5 |
Permission is hereby granted, free of charge, to any person obtaining a copy |
@@ -23,8 +23,8 @@ |
||
| 23 | 23 |
|
| 24 | 24 |
|
| 25 | 25 |
|
| 26 |
- You will probably need to tell the editor where to find its add and delete images. In your |
|
| 27 |
- code before you make the editor, do something like this: |
|
| 26 |
+ You will probably need to tell the editor where to find its 'add' and 'delete' images. In your |
|
| 27 |
+ code, before you make the editor, do something like this: |
|
| 28 | 28 |
JSONEditor.prototype.ADD_IMG = '/javascripts/jsoneditor/add.png'; |
| 29 | 29 |
JSONEditor.prototype.DELETE_IMG = '/javascripts/jsoneditor/delete.png'; |
| 30 | 30 |
|
@@ -36,504 +36,529 @@ |
||
| 36 | 36 |
*/ |
| 37 | 37 |
|
| 38 | 38 |
|
| 39 |
-function JSONEditorBase(options) {
|
|
| 40 |
- if (!options) options = {};
|
|
| 41 |
- this.builderShowing = true; |
|
| 42 |
- this.ADD_IMG = options.ADD_IMG || 'lib/images/add.png'; |
|
| 43 |
- this.DELETE_IMG = options.DELETE_IMG || 'lib/images/delete.png'; |
|
| 44 |
- this.functionButtonsEnabled = false; |
|
| 45 |
- this._doTruncation = true; |
|
| 46 |
- this._showWipe = options.showWipe; |
|
| 47 |
-} |
|
| 48 |
- |
|
| 49 |
-function JSONEditor(wrapped, width, height) {
|
|
| 50 |
- this.history = []; |
|
| 51 |
- this.historyPointer = -1; |
|
| 52 |
- if (wrapped == null || (wrapped.get && wrapped.get(0) == null)) throw "Must provide an element to wrap."; |
|
| 53 |
- var width = width || 600; |
|
| 54 |
- var height = height || 300; |
|
| 55 |
- this.wrapped = $(wrapped); |
|
| 56 |
- |
|
| 57 |
- this.wrapped.wrap('<div class="json-editor"></div>');
|
|
| 58 |
- this.container = $(this.wrapped.parent()); |
|
| 59 |
- this.container.width(width).height(height); |
|
| 60 |
- this.wrapped.width(width).height(height); |
|
| 61 |
- this.wrapped.hide(); |
|
| 62 |
- this.container.css("position", "relative");
|
|
| 63 |
- this.doAutoFocus = false; |
|
| 64 |
- this.editingUnfocused(); |
|
| 65 |
- |
|
| 66 |
- this.rebuild(); |
|
| 67 |
- var self = this; |
|
| 68 |
- this.container.focus(function(){
|
|
| 69 |
- $(this).children('textarea').height(self.container.height() - self.functionButtons.height() - 5);
|
|
| 70 |
- $(this).children('.builder').height(self.container.height() - self.functionButtons.height() - 10);
|
|
| 71 |
- }); |
|
| 72 |
- |
|
| 73 |
- return this; |
|
| 74 |
-} |
|
| 75 |
-JSONEditor.prototype = new JSONEditorBase(); |
|
| 76 |
- |
|
| 77 |
-JSONEditor.prototype.braceUI = function(key, struct) {
|
|
| 78 |
- var self = this; |
|
| 79 |
- return $('<a class="icon" href="#"><strong>{</strong></a>').click(function(e) {
|
|
| 80 |
- struct[key] = { "??": struct[key] };
|
|
| 81 |
- self.doAutoFocus = true; |
|
| 82 |
- self.rebuild(); |
|
| 83 |
- return false; |
|
| 84 |
- }); |
|
| 85 |
-}; |
|
| 86 |
- |
|
| 87 |
-JSONEditor.prototype.bracketUI = function(key, struct) {
|
|
| 88 |
- var self = this; |
|
| 89 |
- return $('<a class="icon" href="#"><strong>[</a>').click(function(e) {
|
|
| 90 |
- struct[key] = [ struct[key] ]; |
|
| 91 |
- self.doAutoFocus = true; |
|
| 92 |
- self.rebuild(); |
|
| 93 |
- return false; |
|
| 94 |
- }); |
|
| 95 |
-}; |
|
| 96 |
- |
|
| 97 |
-JSONEditor.prototype.deleteUI = function(key, struct, fullDelete) {
|
|
| 98 |
- var self = this; |
|
| 99 |
- return $('<a class="icon" href="#" title="delete"><img src="' + this.DELETE_IMG + '" border=0/></a>').click(function(e) {
|
|
| 100 |
- if (!fullDelete) {
|
|
| 101 |
- var didSomething = false; |
|
| 102 |
- if (struct[key] instanceof Array) {
|
|
| 103 |
- if(struct[key].length > 0) {
|
|
| 104 |
- struct[key] = struct[key][0]; |
|
| 105 |
- didSomething = true; |
|
| 39 |
+(function() {
|
|
| 40 |
+ |
|
| 41 |
+ window.JSONEditor = (function() {
|
|
| 42 |
+ |
|
| 43 |
+ function JSONEditor(wrapped, options) {
|
|
| 44 |
+ if (options == null) {
|
|
| 45 |
+ options = {};
|
|
| 46 |
+ } |
|
| 47 |
+ this.builderShowing = true; |
|
| 48 |
+ this.ADD_IMG || (this.ADD_IMG = options.ADD_IMG || 'lib/images/add.png'); |
|
| 49 |
+ this.DELETE_IMG || (this.DELETE_IMG = options.DELETE_IMG || 'lib/images/delete.png'); |
|
| 50 |
+ this.functionButtonsEnabled = false; |
|
| 51 |
+ this._doTruncation = true; |
|
| 52 |
+ this._showWipe = options.showWipe; |
|
| 53 |
+ this.history = []; |
|
| 54 |
+ this.historyPointer = -1; |
|
| 55 |
+ if (wrapped === null || (wrapped.get && wrapped.get(0) === null)) {
|
|
| 56 |
+ throw "Must provide an element to wrap."; |
|
| 57 |
+ } |
|
| 58 |
+ this.wrapped = $(wrapped); |
|
| 59 |
+ this.wrapped.wrap('<div class="json-editor"></div>');
|
|
| 60 |
+ this.container = $(this.wrapped.parent()); |
|
| 61 |
+ this.wrapped.hide(); |
|
| 62 |
+ this.container.css("position", "relative");
|
|
| 63 |
+ this.doAutoFocus = false; |
|
| 64 |
+ this.editingUnfocused(); |
|
| 65 |
+ this.rebuild(); |
|
| 66 |
+ } |
|
| 67 |
+ |
|
| 68 |
+ JSONEditor.prototype.braceUI = function(key, struct) {
|
|
| 69 |
+ var _this = this; |
|
| 70 |
+ return $('<a class="icon" href="#"><strong>{</strong></a>').click(function(e) {
|
|
| 71 |
+ e.preventDefault(); |
|
| 72 |
+ struct[key] = {
|
|
| 73 |
+ "??": struct[key] |
|
| 74 |
+ }; |
|
| 75 |
+ _this.doAutoFocus = true; |
|
| 76 |
+ return _this.rebuild(); |
|
| 77 |
+ }); |
|
| 78 |
+ }; |
|
| 79 |
+ |
|
| 80 |
+ JSONEditor.prototype.bracketUI = function(key, struct) {
|
|
| 81 |
+ var _this = this; |
|
| 82 |
+ return $('<a class="icon" href="#"><strong>[</a>').click(function(e) {
|
|
| 83 |
+ e.preventDefault(); |
|
| 84 |
+ struct[key] = [struct[key]]; |
|
| 85 |
+ _this.doAutoFocus = true; |
|
| 86 |
+ return _this.rebuild(); |
|
| 87 |
+ }); |
|
| 88 |
+ }; |
|
| 89 |
+ |
|
| 90 |
+ JSONEditor.prototype.deleteUI = function(key, struct, fullDelete) {
|
|
| 91 |
+ var _this = this; |
|
| 92 |
+ return $("<a class='icon' href='#' title='delete'><img src='" + this.DELETE_IMG + "' border=0 /></a>").click(function(e) {
|
|
| 93 |
+ var didSomething, subkey, subval, _ref; |
|
| 94 |
+ e.preventDefault(); |
|
| 95 |
+ if (!fullDelete) {
|
|
| 96 |
+ didSomething = false; |
|
| 97 |
+ if (struct[key] instanceof Array) {
|
|
| 98 |
+ if (struct[key].length > 0) {
|
|
| 99 |
+ struct[key] = struct[key][0]; |
|
| 100 |
+ didSomething = true; |
|
| 101 |
+ } |
|
| 102 |
+ } else if (struct[key] instanceof Object) {
|
|
| 103 |
+ _ref = struct[key]; |
|
| 104 |
+ for (subkey in _ref) {
|
|
| 105 |
+ subval = _ref[subkey]; |
|
| 106 |
+ struct[key] = struct[key][subkey]; |
|
| 107 |
+ didSomething = true; |
|
| 108 |
+ break; |
|
| 109 |
+ } |
|
| 110 |
+ } |
|
| 111 |
+ if (didSomething) {
|
|
| 112 |
+ _this.rebuild(); |
|
| 113 |
+ return; |
|
| 114 |
+ } |
|
| 106 | 115 |
} |
| 107 |
- } else if (struct[key] instanceof Object) {
|
|
| 108 |
- for (var i in struct[key]) {
|
|
| 109 |
- struct[key] = struct[key][i]; |
|
| 110 |
- didSomething = true; |
|
| 111 |
- break; |
|
| 116 |
+ if (struct instanceof Array) {
|
|
| 117 |
+ struct.splice(key, 1); |
|
| 118 |
+ } else {
|
|
| 119 |
+ delete struct[key]; |
|
| 120 |
+ } |
|
| 121 |
+ return _this.rebuild(); |
|
| 122 |
+ }); |
|
| 123 |
+ }; |
|
| 124 |
+ |
|
| 125 |
+ JSONEditor.prototype.wipeUI = function(key, struct) {
|
|
| 126 |
+ var _this = this; |
|
| 127 |
+ return $('<a class="icon" href="#" title="wipe"><strong>W</strong></a>').click(function(e) {
|
|
| 128 |
+ e.preventDefault(); |
|
| 129 |
+ if (struct instanceof Array) {
|
|
| 130 |
+ struct.splice(key, 1); |
|
| 131 |
+ } else {
|
|
| 132 |
+ delete struct[key]; |
|
| 133 |
+ } |
|
| 134 |
+ return _this.rebuild(); |
|
| 135 |
+ }); |
|
| 136 |
+ }; |
|
| 137 |
+ |
|
| 138 |
+ JSONEditor.prototype.addUI = function(struct) {
|
|
| 139 |
+ var _this = this; |
|
| 140 |
+ return $("<a class='icon' href='#' title='add'><img src='" + this.ADD_IMG + "' border=0/></a>").click(function(e) {
|
|
| 141 |
+ e.preventDefault(); |
|
| 142 |
+ if (struct instanceof Array) {
|
|
| 143 |
+ struct.push('??');
|
|
| 144 |
+ } else {
|
|
| 145 |
+ struct['??'] = '??'; |
|
| 146 |
+ } |
|
| 147 |
+ _this.doAutoFocus = true; |
|
| 148 |
+ return _this.rebuild(); |
|
| 149 |
+ }); |
|
| 150 |
+ }; |
|
| 151 |
+ |
|
| 152 |
+ JSONEditor.prototype.undo = function() {
|
|
| 153 |
+ if (this.saveStateIfTextChanged()) {
|
|
| 154 |
+ if (this.historyPointer > 0) {
|
|
| 155 |
+ this.historyPointer -= 1; |
|
| 156 |
+ } |
|
| 157 |
+ return this.restore(); |
|
| 158 |
+ } |
|
| 159 |
+ }; |
|
| 160 |
+ |
|
| 161 |
+ JSONEditor.prototype.redo = function() {
|
|
| 162 |
+ if (this.historyPointer + 1 < this.history.length) {
|
|
| 163 |
+ if (this.saveStateIfTextChanged()) {
|
|
| 164 |
+ this.historyPointer += 1; |
|
| 165 |
+ return this.restore(); |
|
| 112 | 166 |
} |
| 113 | 167 |
} |
| 114 |
- if (didSomething) {
|
|
| 115 |
- self.rebuild(); |
|
| 168 |
+ }; |
|
| 169 |
+ |
|
| 170 |
+ JSONEditor.prototype.showBuilder = function() {
|
|
| 171 |
+ if (this.checkJsonInText()) {
|
|
| 172 |
+ this.setJsonFromText(); |
|
| 173 |
+ this.rebuild(); |
|
| 174 |
+ this.wrapped.hide(); |
|
| 175 |
+ this.builder.show(); |
|
| 176 |
+ return true; |
|
| 177 |
+ } else {
|
|
| 178 |
+ alert("Sorry, there appears to be an error in your JSON input. Please fix it before continuing.");
|
|
| 116 | 179 |
return false; |
| 117 | 180 |
} |
| 118 |
- } |
|
| 119 |
- if (struct instanceof Array) {
|
|
| 120 |
- struct.splice(key, 1); |
|
| 121 |
- } else {
|
|
| 122 |
- delete struct[key]; |
|
| 123 |
- } |
|
| 124 |
- self.rebuild(); |
|
| 125 |
- return false; |
|
| 126 |
- }); |
|
| 127 |
-}; |
|
| 128 |
- |
|
| 129 |
-JSONEditor.prototype.wipeUI = function(key, struct) {
|
|
| 130 |
- var self = this; |
|
| 131 |
- return $('<a class="icon" href="#" title="wipe"><strong>W</strong></a>').click(function(e) {
|
|
| 132 |
- if (struct instanceof Array) {
|
|
| 133 |
- struct.splice(key, 1); |
|
| 134 |
- } else {
|
|
| 135 |
- delete struct[key]; |
|
| 136 |
- } |
|
| 137 |
- self.rebuild(); |
|
| 138 |
- return false; |
|
| 139 |
- }); |
|
| 140 |
-}; |
|
| 141 |
- |
|
| 142 |
-JSONEditor.prototype.addUI = function(struct) {
|
|
| 143 |
- var self = this; |
|
| 144 |
- return $('<a class="icon" href="#" title="add"><img src="' + this.ADD_IMG + '" border=0/></a>').click(function(e) {
|
|
| 145 |
- if (struct instanceof Array) {
|
|
| 146 |
- struct.push('??');
|
|
| 147 |
- } else {
|
|
| 148 |
- struct['??'] = '??'; |
|
| 149 |
- } |
|
| 150 |
- self.doAutoFocus = true; |
|
| 151 |
- self.rebuild(); |
|
| 152 |
- return false; |
|
| 153 |
- }); |
|
| 154 |
-}; |
|
| 155 |
- |
|
| 156 |
-JSONEditor.prototype.undo = function() {
|
|
| 157 |
- if (this.saveStateIfTextChanged()) {
|
|
| 158 |
- if (this.historyPointer > 0) this.historyPointer -= 1; |
|
| 159 |
- this.restore(); |
|
| 160 |
- } |
|
| 161 |
-}; |
|
| 162 |
- |
|
| 163 |
-JSONEditor.prototype.redo = function() {
|
|
| 164 |
- if (this.historyPointer + 1 < this.history.length) {
|
|
| 165 |
- if (this.saveStateIfTextChanged()) {
|
|
| 166 |
- this.historyPointer += 1; |
|
| 167 |
- this.restore(); |
|
| 168 |
- } |
|
| 169 |
- } |
|
| 170 |
-}; |
|
| 171 |
- |
|
| 172 |
-JSONEditor.prototype.showBuilder = function() {
|
|
| 173 |
- if (this.checkJsonInText()) {
|
|
| 174 |
- this.setJsonFromText(); |
|
| 175 |
- this.rebuild(); |
|
| 176 |
- this.wrapped.hide(); |
|
| 177 |
- this.builder.show(); |
|
| 178 |
- return true; |
|
| 179 |
- } else {
|
|
| 180 |
- alert("Sorry, there appears to be an error in your JSON input. Please fix it before continuing.");
|
|
| 181 |
- return false; |
|
| 182 |
- } |
|
| 183 |
-}; |
|
| 184 |
- |
|
| 185 |
-JSONEditor.prototype.showText = function() {
|
|
| 186 |
- this.builder.hide(); |
|
| 187 |
- this.wrapped.show(); |
|
| 188 |
-}; |
|
| 189 |
- |
|
| 190 |
-JSONEditor.prototype.toggleBuilder = function() {
|
|
| 191 |
- if(this.builderShowing){
|
|
| 192 |
- this.showText(); |
|
| 193 |
- this.builderShowing = !this.builderShowing; |
|
| 194 |
- } else {
|
|
| 195 |
- if (this.showBuilder()) {
|
|
| 196 |
- this.builderShowing = !this.builderShowing; |
|
| 181 |
+ }; |
|
| 182 |
+ |
|
| 183 |
+ JSONEditor.prototype.showText = function() {
|
|
| 184 |
+ this.builder.hide(); |
|
| 185 |
+ return this.wrapped.show(); |
|
| 186 |
+ }; |
|
| 187 |
+ |
|
| 188 |
+ JSONEditor.prototype.toggleBuilder = function() {
|
|
| 189 |
+ if (this.builderShowing) {
|
|
| 190 |
+ this.showText(); |
|
| 191 |
+ return this.builderShowing = !this.builderShowing; |
|
| 192 |
+ } else {
|
|
| 193 |
+ if (this.showBuilder()) {
|
|
| 194 |
+ return this.builderShowing = !this.builderShowing; |
|
| 195 |
+ } |
|
| 197 | 196 |
} |
| 198 |
- } |
|
| 199 |
-}; |
|
| 200 |
- |
|
| 201 |
-JSONEditor.prototype.showFunctionButtons = function(insider) {
|
|
| 202 |
- if (!insider) this.functionButtonsEnabled = true; |
|
| 203 |
- if (this.functionButtonsEnabled) if (!this.functionButtons) {
|
|
| 204 |
- this.functionButtons = $('<div class="function_buttons"></div>');
|
|
| 205 |
- var self = this; |
|
| 206 |
- this.functionButtons.append($('<a href="#" style="padding-right: 10px;"></a>').click(function() {
|
|
| 207 |
- self.undo(); |
|
| 208 |
- return false; |
|
| 209 |
- }).text('Undo')).append($('<a href="#" style="padding-right: 10px;"></a>').click(function() {
|
|
| 210 |
- self.redo(); |
|
| 211 |
- return false; |
|
| 212 |
- }).text('Redo')).append($('<a id="toggle_view" href="#" style="padding-right: 10px;"></a>').click(function() {
|
|
| 213 |
- self.toggleBuilder(); |
|
| 214 |
- return false; |
|
| 215 |
- }).text('Toggle View'));
|
|
| 216 |
- this.container.prepend(this.functionButtons); |
|
| 217 |
- this.container.height(this.container.height() + this.functionButtons.height() + 5); |
|
| 218 |
- } |
|
| 219 |
- if (this.functionButtons) {
|
|
| 220 |
- this.wrapped.css('top', this.functionButtons.height() + 5 + 'px');
|
|
| 221 |
- this.builder.css('top', this.functionButtons.height() + 5 + 'px');
|
|
| 222 |
- } |
|
| 223 |
-}; |
|
| 224 |
- |
|
| 225 |
-JSONEditor.prototype.saveStateIfTextChanged = function() {
|
|
| 226 |
- if (JSON.stringify(this.json, null, 2) != this.wrapped.get(0).value) {
|
|
| 227 |
- if (this.checkJsonInText()) {
|
|
| 228 |
- this.saveState(true); |
|
| 229 |
- } else {
|
|
| 230 |
- if (confirm("The current JSON is malformed. If you continue, the current JSON will not be saved. Do you wish to continue?")) {
|
|
| 231 |
- this.historyPointer += 1; |
|
| 197 |
+ }; |
|
| 198 |
+ |
|
| 199 |
+ JSONEditor.prototype.showFunctionButtons = function(insider) {
|
|
| 200 |
+ var _this = this; |
|
| 201 |
+ if (!insider) {
|
|
| 202 |
+ this.functionButtonsEnabled = true; |
|
| 203 |
+ } |
|
| 204 |
+ if (this.functionButtonsEnabled && !this.functionButtons) {
|
|
| 205 |
+ this.functionButtons = $('<div class="function_buttons"></div>');
|
|
| 206 |
+ this.functionButtons.append($('<a href="#" style="padding-right: 10px;">Undo</a>').click(function(e) {
|
|
| 207 |
+ e.preventDefault(); |
|
| 208 |
+ return _this.undo(); |
|
| 209 |
+ })); |
|
| 210 |
+ this.functionButtons.append($('<a href="#" style="padding-right: 10px;">Redo</a>').click(function(e) {
|
|
| 211 |
+ e.preventDefault(); |
|
| 212 |
+ return _this.redo(); |
|
| 213 |
+ })); |
|
| 214 |
+ this.functionButtons.append($('<a id="toggle_view" href="#" style="padding-right: 10px; float: right;">Toggle View</a>').click(function(e) {
|
|
| 215 |
+ e.preventDefault(); |
|
| 216 |
+ return _this.toggleBuilder(); |
|
| 217 |
+ })); |
|
| 218 |
+ return this.container.prepend(this.functionButtons); |
|
| 219 |
+ } |
|
| 220 |
+ }; |
|
| 221 |
+ |
|
| 222 |
+ JSONEditor.prototype.saveStateIfTextChanged = function() {
|
|
| 223 |
+ if (JSON.stringify(this.json, null, 2) !== this.wrapped.get(0).value) {
|
|
| 224 |
+ if (this.checkJsonInText()) {
|
|
| 225 |
+ this.saveState(true); |
|
| 226 |
+ } else {
|
|
| 227 |
+ if (confirm("The current JSON is malformed. If you continue, the current JSON will not be saved. Do you wish to continue?")) {
|
|
| 228 |
+ this.historyPointer += 1; |
|
| 229 |
+ true; |
|
| 230 |
+ } else {
|
|
| 231 |
+ false; |
|
| 232 |
+ } |
|
| 233 |
+ } |
|
| 234 |
+ } |
|
| 235 |
+ return true; |
|
| 236 |
+ }; |
|
| 237 |
+ |
|
| 238 |
+ JSONEditor.prototype.restore = function() {
|
|
| 239 |
+ if (this.history[this.historyPointer]) {
|
|
| 240 |
+ this.wrapped.get(0).value = this.history[this.historyPointer]; |
|
| 241 |
+ return this.rebuild(true); |
|
| 242 |
+ } |
|
| 243 |
+ }; |
|
| 244 |
+ |
|
| 245 |
+ JSONEditor.prototype.saveState = function(skipStoreText) {
|
|
| 246 |
+ var text; |
|
| 247 |
+ if (this.json) {
|
|
| 248 |
+ if (!skipStoreText) {
|
|
| 249 |
+ this.storeToText(); |
|
| 250 |
+ } |
|
| 251 |
+ text = this.wrapped.get(0).value; |
|
| 252 |
+ if (this.history[this.historyPointer] !== text) {
|
|
| 253 |
+ this.historyTruncate(); |
|
| 254 |
+ this.history.push(text); |
|
| 255 |
+ return this.historyPointer += 1; |
|
| 256 |
+ } |
|
| 257 |
+ } |
|
| 258 |
+ }; |
|
| 259 |
+ |
|
| 260 |
+ JSONEditor.prototype.fireChange = function() {
|
|
| 261 |
+ return $(this.wrapped).trigger('change');
|
|
| 262 |
+ }; |
|
| 263 |
+ |
|
| 264 |
+ JSONEditor.prototype.historyTruncate = function() {
|
|
| 265 |
+ if (this.historyPointer + 1 < this.history.length) {
|
|
| 266 |
+ return this.history.splice(this.historyPointer + 1, this.history.length - this.historyPointer); |
|
| 267 |
+ } |
|
| 268 |
+ }; |
|
| 269 |
+ |
|
| 270 |
+ JSONEditor.prototype.storeToText = function() {
|
|
| 271 |
+ return this.wrapped.get(0).value = JSON.stringify(this.json, null, 2); |
|
| 272 |
+ }; |
|
| 273 |
+ |
|
| 274 |
+ JSONEditor.prototype.getJSONText = function() {
|
|
| 275 |
+ this.rebuild(); |
|
| 276 |
+ return this.wrapped.get(0).value; |
|
| 277 |
+ }; |
|
| 278 |
+ |
|
| 279 |
+ JSONEditor.prototype.getJSON = function() {
|
|
| 280 |
+ this.rebuild(); |
|
| 281 |
+ return this.json; |
|
| 282 |
+ }; |
|
| 283 |
+ |
|
| 284 |
+ JSONEditor.prototype.rebuild = function(doNotRefreshText) {
|
|
| 285 |
+ var changed, elem; |
|
| 286 |
+ if (!this.json) {
|
|
| 287 |
+ this.setJsonFromText(); |
|
| 288 |
+ } |
|
| 289 |
+ changed = this.haveThingsChanged(); |
|
| 290 |
+ if (this.json && !doNotRefreshText) {
|
|
| 291 |
+ this.saveState(); |
|
| 292 |
+ } |
|
| 293 |
+ this.cleanBuilder(); |
|
| 294 |
+ this.setJsonFromText(); |
|
| 295 |
+ this.alreadyFocused = false; |
|
| 296 |
+ elem = this.build(this.json, this.builder, null, null, this.json); |
|
| 297 |
+ this.recoverScrollPosition(); |
|
| 298 |
+ if (elem && elem.text() === '??' && !this.alreadyFocused && this.doAutoFocus) {
|
|
| 299 |
+ this.alreadyFocused = true; |
|
| 300 |
+ this.doAutoFocus = false; |
|
| 301 |
+ elem = elem.find('.editable');
|
|
| 302 |
+ elem.click(); |
|
| 303 |
+ elem.find('input').focus().select();
|
|
| 304 |
+ } |
|
| 305 |
+ if (changed) {
|
|
| 306 |
+ return this.fireChange(); |
|
| 307 |
+ } |
|
| 308 |
+ }; |
|
| 309 |
+ |
|
| 310 |
+ JSONEditor.prototype.haveThingsChanged = function() {
|
|
| 311 |
+ return this.json && JSON.stringify(this.json, null, 2) !== this.wrapped.get(0).value; |
|
| 312 |
+ }; |
|
| 313 |
+ |
|
| 314 |
+ JSONEditor.prototype.saveScrollPosition = function() {
|
|
| 315 |
+ return this.oldScrollHeight = this.builder.scrollTop(); |
|
| 316 |
+ }; |
|
| 317 |
+ |
|
| 318 |
+ JSONEditor.prototype.recoverScrollPosition = function() {
|
|
| 319 |
+ return this.builder.scrollTop(this.oldScrollHeight); |
|
| 320 |
+ }; |
|
| 321 |
+ |
|
| 322 |
+ JSONEditor.prototype.setJsonFromText = function() {
|
|
| 323 |
+ if (this.wrapped.get(0).value.length === 0) {
|
|
| 324 |
+ this.wrapped.get(0).value = "{}";
|
|
| 325 |
+ } |
|
| 326 |
+ try {
|
|
| 327 |
+ this.wrapped.get(0).value = this.wrapped.get(0).value.replace(/((^|[^\\])(\\\\)*)\\n/g, '$1\\\\n').replace(/((^|[^\\])(\\\\)*)\\t/g, '$1\\\\t'); |
|
| 328 |
+ return this.json = JSON.parse(this.wrapped.get(0).value); |
|
| 329 |
+ } catch (e) {
|
|
| 330 |
+ return alert("Got bad JSON from text.");
|
|
| 331 |
+ } |
|
| 332 |
+ }; |
|
| 333 |
+ |
|
| 334 |
+ JSONEditor.prototype.checkJsonInText = function() {
|
|
| 335 |
+ try {
|
|
| 336 |
+ JSON.parse(this.wrapped.get(0).value); |
|
| 232 | 337 |
return true; |
| 233 |
- } else {
|
|
| 338 |
+ } catch (e) {
|
|
| 234 | 339 |
return false; |
| 235 | 340 |
} |
| 236 |
- } |
|
| 237 |
- } |
|
| 238 |
- return true; |
|
| 239 |
-}; |
|
| 240 |
- |
|
| 241 |
-JSONEditor.prototype.restore = function() {
|
|
| 242 |
- if (this.history[this.historyPointer]) {
|
|
| 243 |
- this.wrapped.get(0).value = this.history[this.historyPointer]; |
|
| 244 |
- this.rebuild(true); |
|
| 245 |
- } |
|
| 246 |
-}; |
|
| 247 |
- |
|
| 248 |
-JSONEditor.prototype.saveState = function(skipStoreText) {
|
|
| 249 |
- if (this.json) {
|
|
| 250 |
- if (!skipStoreText) this.storeToText(); |
|
| 251 |
- var text = this.wrapped.get(0).value; |
|
| 252 |
- if (this.history[this.historyPointer] != text) {
|
|
| 253 |
- this.historyTruncate(); |
|
| 254 |
- this.history.push(text); |
|
| 255 |
- this.historyPointer += 1; |
|
| 256 |
- } |
|
| 257 |
- } |
|
| 258 |
-}; |
|
| 259 |
- |
|
| 260 |
-JSONEditor.prototype.fireChange = function() {
|
|
| 261 |
- $(this.wrapped).trigger('change');
|
|
| 262 |
-}; |
|
| 263 |
- |
|
| 264 |
-JSONEditor.prototype.historyTruncate = function() {
|
|
| 265 |
- if (this.historyPointer + 1 < this.history.length) {
|
|
| 266 |
- this.history.splice(this.historyPointer + 1, this.history.length - this.historyPointer); |
|
| 267 |
- } |
|
| 268 |
-}; |
|
| 269 |
- |
|
| 270 |
-JSONEditor.prototype.storeToText = function() {
|
|
| 271 |
- this.wrapped.get(0).value = JSON.stringify(this.json, null, 2); |
|
| 272 |
-}; |
|
| 273 |
- |
|
| 274 |
-JSONEditor.prototype.getJSONText = function() {
|
|
| 275 |
- this.rebuild(); |
|
| 276 |
- return this.wrapped.get(0).value; |
|
| 277 |
-}; |
|
| 278 |
- |
|
| 279 |
-JSONEditor.prototype.getJSON = function() {
|
|
| 280 |
- this.rebuild(); |
|
| 281 |
- return this.json; |
|
| 282 |
-}; |
|
| 283 |
- |
|
| 284 |
-JSONEditor.prototype.rebuild = function(doNotRefreshText) {
|
|
| 285 |
- if (!this.json) this.setJsonFromText(); |
|
| 286 |
- var changed = this.haveThingsChanged(); |
|
| 287 |
- if (this.json && !doNotRefreshText) {
|
|
| 288 |
- this.saveState(); |
|
| 289 |
- } |
|
| 290 |
- this.cleanBuilder(); |
|
| 291 |
- this.setJsonFromText(); |
|
| 292 |
- this.alreadyFocused = false; |
|
| 293 |
- var elem = this.build(this.json, this.builder, null, null, this.json); |
|
| 294 |
- |
|
| 295 |
- this.recoverScrollPosition(); |
|
| 296 |
- |
|
| 297 |
- // Auto-focus to edit '??' keys and values. |
|
| 298 |
- if (elem) if (elem.text() == '??' && !this.alreadyFocused && this.doAutoFocus) {
|
|
| 299 |
- this.alreadyFocused = true; |
|
| 300 |
- this.doAutoFocus = false; |
|
| 301 |
- |
|
| 302 |
- elem = elem.find('.editable');
|
|
| 303 |
- elem.click(); |
|
| 304 |
- elem.find('input').focus().select();
|
|
| 305 |
- //still missing a proper scrolling into the selected input |
|
| 306 |
- } |
|
| 307 |
- |
|
| 308 |
- if (changed) this.fireChange(); |
|
| 309 |
-}; |
|
| 310 |
- |
|
| 311 |
-JSONEditor.prototype.haveThingsChanged = function() {
|
|
| 312 |
- return (this.json && JSON.stringify(this.json, null, 2) != this.wrapped.get(0).value); |
|
| 313 |
-} |
|
| 314 |
- |
|
| 315 |
-JSONEditor.prototype.saveScrollPosition = function() {
|
|
| 316 |
- this.oldScrollHeight = this.builder.scrollTop(); |
|
| 317 |
-}; |
|
| 318 |
- |
|
| 319 |
-JSONEditor.prototype.recoverScrollPosition = function() {
|
|
| 320 |
- this.builder.scrollTop(this.oldScrollHeight); |
|
| 321 |
-}; |
|
| 322 |
- |
|
| 323 |
-JSONEditor.prototype.setJsonFromText = function() {
|
|
| 324 |
- if (this.wrapped.get(0).value.length == 0) this.wrapped.get(0).value = "{}";
|
|
| 325 |
- try {
|
|
| 326 |
- this.wrapped.get(0).value = this.wrapped.get(0).value.replace(/((^|[^\\])(\\\\)*)\\n/g, '$1\\\\n').replace(/((^|[^\\])(\\\\)*)\\t/g, '$1\\\\t'); |
|
| 327 |
- this.json = JSON.parse(this.wrapped.get(0).value); |
|
| 328 |
- } catch(e) {
|
|
| 329 |
- alert("Got bad JSON from text.");
|
|
| 330 |
- } |
|
| 331 |
-}; |
|
| 332 |
- |
|
| 333 |
-JSONEditor.prototype.checkJsonInText = function() {
|
|
| 334 |
- try {
|
|
| 335 |
- JSON.parse(this.wrapped.get(0).value); |
|
| 336 |
- return true; |
|
| 337 |
- } catch(e) {
|
|
| 338 |
- return false; |
|
| 339 |
- } |
|
| 340 |
-}; |
|
| 341 |
- |
|
| 342 |
-JSONEditor.prototype.logJSON = function() {
|
|
| 343 |
- console.log(JSON.stringify(this.json, null, 2)); |
|
| 344 |
-}; |
|
| 345 |
- |
|
| 346 |
-JSONEditor.prototype.cleanBuilder = function() {
|
|
| 347 |
- if (!this.builder) {
|
|
| 348 |
- this.builder = $('<div class="builder"></div>');
|
|
| 349 |
- this.container.append(this.builder); |
|
| 350 |
- } |
|
| 351 |
- this.saveScrollPosition(); |
|
| 352 |
- this.builder.text('');
|
|
| 353 |
- |
|
| 354 |
- this.builder.css("position", "absolute").css("top", 0).css("left", 0);
|
|
| 355 |
- this.builder.width(this.wrapped.width()).height(this.wrapped.height()); |
|
| 356 |
- this.wrapped.css("position", "absolute").css("top", 0).css("left", 0);
|
|
| 357 |
- this.showFunctionButtons("defined");
|
|
| 358 |
-}; |
|
| 359 |
- |
|
| 360 |
-JSONEditor.prototype.updateStruct = function(struct, key, val, kind, selectionStart, selectionEnd) {
|
|
| 361 |
- if(kind == 'key') {
|
|
| 362 |
- if (selectionStart && selectionEnd) val = key.substring(0, selectionStart) + val + key.substring(selectionEnd, key.length); |
|
| 363 |
- struct[val] = struct[key]; |
|
| 364 |
- |
|
| 365 |
- //order keys |
|
| 366 |
- var orderrest = 0; |
|
| 367 |
- $.each(struct, function (index, value) {
|
|
| 368 |
- //re set rest of the keys |
|
| 369 |
- if(orderrest & index != val) {
|
|
| 370 |
- var tempval = struct[index]; |
|
| 371 |
- delete struct[index]; |
|
| 372 |
- struct[index] = tempval; |
|
| 373 |
- } |
|
| 374 |
- if(key == index) {
|
|
| 375 |
- orderrest = 1; |
|
| 376 |
- } |
|
| 377 |
- }); |
|
| 378 |
- // end of order keys |
|
| 379 |
- |
|
| 380 |
- if (key != val) delete struct[key]; |
|
| 381 |
- } else {
|
|
| 382 |
- if (selectionStart && selectionEnd) val = struct[key].substring(0, selectionStart) + val + struct[key].substring(selectionEnd, struct[key].length); |
|
| 383 |
- struct[key] = val; |
|
| 384 |
- } |
|
| 385 |
-}; |
|
| 386 |
- |
|
| 387 |
-JSONEditor.prototype.getValFromStruct = function(struct, key, kind) {
|
|
| 388 |
- if(kind == 'key') {
|
|
| 389 |
- return key; |
|
| 390 |
- } else {
|
|
| 391 |
- return struct[key]; |
|
| 392 |
- } |
|
| 393 |
-}; |
|
| 394 |
- |
|
| 395 |
-JSONEditor.prototype.doTruncation = function(trueOrFalse) {
|
|
| 396 |
- if (this._doTruncation != trueOrFalse) {
|
|
| 397 |
- this._doTruncation = trueOrFalse; |
|
| 398 |
- this.rebuild(); |
|
| 399 |
- } |
|
| 400 |
-}; |
|
| 401 |
- |
|
| 402 |
-JSONEditor.prototype.showWipe = function(trueOrFalse) {
|
|
| 403 |
- if (this._showWipe != trueOrFalse) {
|
|
| 404 |
- this._showWipe = trueOrFalse; |
|
| 405 |
- this.rebuild(); |
|
| 406 |
- } |
|
| 407 |
-}; |
|
| 408 |
- |
|
| 409 |
-JSONEditor.prototype.truncate = function(text, length) {
|
|
| 410 |
- if (text.length == 0) return '-empty-'; |
|
| 411 |
- if(this._doTruncation && text.length > (length || 30)) return(text.substring(0, (length || 30)) + '...'); |
|
| 412 |
- return text; |
|
| 413 |
-}; |
|
| 414 |
- |
|
| 415 |
-JSONEditor.prototype.replaceLastSelectedFieldIfRecent = function(text) {
|
|
| 416 |
- if (this.lastEditingUnfocusedTime > (new Date()).getTime() - 200) { // Short delay for unfocus to occur.
|
|
| 417 |
- this.setLastEditingFocus(text); |
|
| 418 |
- this.rebuild(); |
|
| 419 |
- } |
|
| 420 |
-}; |
|
| 421 |
- |
|
| 422 |
-JSONEditor.prototype.editingUnfocused = function(elem, struct, key, root, kind) {
|
|
| 423 |
- var self = this; |
|
| 424 |
- |
|
| 425 |
- var selectionStart = elem && elem.target.selectionStart; |
|
| 426 |
- var selectionEnd = elem && elem.target.selectionEnd; |
|
| 427 |
- |
|
| 428 |
- this.setLastEditingFocus = function(text) {
|
|
| 429 |
- self.updateStruct(struct, key, text, kind, selectionStart, selectionEnd); |
|
| 430 |
- self.json = root; // Because self.json is a new reference due to rebuild. |
|
| 431 |
- }; |
|
| 432 |
- this.lastEditingUnfocusedTime = (new Date()).getTime(); |
|
| 433 |
-}; |
|
| 434 |
- |
|
| 435 |
-JSONEditor.prototype.edit = function(e, key, struct, root, kind){
|
|
| 436 |
- var self = this; |
|
| 437 |
- var form = $("<form></form>").css('display', 'inline');
|
|
| 438 |
- var input = document.createElement("INPUT");
|
|
| 439 |
- input.value = this.getValFromStruct(struct, key, kind); |
|
| 440 |
- //alert(this.getValFromStruct(struct, key, kind)); |
|
| 441 |
- input.className = 'edit_field'; |
|
| 442 |
- var onblur = function(elem) {
|
|
| 443 |
- var val = input.value; |
|
| 444 |
- self.updateStruct(struct, key, val, kind); |
|
| 445 |
- self.editingUnfocused(elem, struct, (kind == 'key' ? val : key), root, kind); |
|
| 446 |
- e.text(self.truncate(val)); |
|
| 447 |
- e.get(0).editing = false; |
|
| 448 |
- if (key != val) self.rebuild(); |
|
| 449 |
- return false; |
|
| 450 |
- }; |
|
| 451 |
- $(input).blur(onblur); |
|
| 452 |
- $(input).keydown(function(e) {
|
|
| 453 |
- if (e.keyCode == 9 || e.keyCode == 13) { // Tab and enter
|
|
| 454 |
- self.doAutoFocus = true; |
|
| 455 |
- onblur(e); |
|
| 456 |
- return false; |
|
| 457 |
- } |
|
| 458 |
- }); |
|
| 459 |
- $(form).submit(function(e) { self.doAutoFocus = true; onblur(e); return false;}).append(input);
|
|
| 460 |
- $(e).html(form); |
|
| 461 |
- input.focus(); |
|
| 462 |
-}; |
|
| 463 |
- |
|
| 464 |
-JSONEditor.prototype.editable = function(text, key, struct, root, kind) {
|
|
| 465 |
- var self = this; |
|
| 466 |
- var elem = $('<span class="editable" href="#"></span>').text(this.truncate(text)).click(function(e) {
|
|
| 467 |
- if (!this.editing) {
|
|
| 468 |
- this.editing = true; |
|
| 469 |
- self.edit($(this), key, struct, root, kind); |
|
| 470 |
- } |
|
| 471 |
- return true; |
|
| 472 |
- }); |
|
| 473 |
- |
|
| 474 |
- return elem; |
|
| 475 |
-} |
|
| 476 |
- |
|
| 477 |
-JSONEditor.prototype.build = function(json, node, parent, key, root) {
|
|
| 478 |
- var elem = null; |
|
| 479 |
- if(json instanceof Array){
|
|
| 480 |
- var bq = $(document.createElement("BLOCKQUOTE"));
|
|
| 481 |
- bq.append($('<div class="brackets">[</div>'));
|
|
| 482 |
- |
|
| 483 |
- bq.prepend(this.addUI(json)); |
|
| 484 |
- if (parent) {
|
|
| 485 |
- if (this._showWipe) bq.prepend(this.wipeUI(key, parent)); |
|
| 486 |
- bq.prepend(this.deleteUI(key, parent)); |
|
| 487 |
- } |
|
| 341 |
+ }; |
|
| 488 | 342 |
|
| 489 |
- for(var i = 0; i < json.length; i++) {
|
|
| 490 |
- var innerbq = $(document.createElement("BLOCKQUOTE"));
|
|
| 491 |
- var newElem = this.build(json[i], innerbq, json, i, root); |
|
| 492 |
- if (newElem) if (newElem.text() == "??") elem = newElem; |
|
| 493 |
- bq.append(innerbq); |
|
| 494 |
- } |
|
| 343 |
+ JSONEditor.prototype.logJSON = function() {
|
|
| 344 |
+ return console.log(JSON.stringify(this.json, null, 2)); |
|
| 345 |
+ }; |
|
| 495 | 346 |
|
| 496 |
- bq.append($('<div class="brackets">]</div>'));
|
|
| 497 |
- node.append(bq); |
|
| 498 |
- } else if (json instanceof Object) {
|
|
| 499 |
- var bq = $(document.createElement("BLOCKQUOTE"));
|
|
| 500 |
- bq.append($('<div class="bracers">{</div>'));
|
|
| 501 |
- |
|
| 502 |
- for(var i in json){
|
|
| 503 |
- var innerbq = $(document.createElement("BLOCKQUOTE"));
|
|
| 504 |
- var newElem = this.editable(i.toString(), i.toString(), json, root, 'key').wrap('<span class="key"></span>').parent();
|
|
| 505 |
- innerbq.append(newElem); |
|
| 506 |
- if (newElem) if (newElem.text() == "??") elem = newElem; |
|
| 507 |
- if (typeof json[i] != 'string' && typeof json[i] != 'number') {
|
|
| 508 |
- innerbq.prepend(this.braceUI(i, json)); |
|
| 509 |
- innerbq.prepend(this.bracketUI(i, json)); |
|
| 510 |
- if (this._showWipe) innerbq.prepend(this.wipeUI(i, json)); |
|
| 511 |
- innerbq.prepend(this.deleteUI(i, json, true)); |
|
| 347 |
+ JSONEditor.prototype.cleanBuilder = function() {
|
|
| 348 |
+ if (!this.builder) {
|
|
| 349 |
+ this.builder = $('<div class="builder"></div>');
|
|
| 350 |
+ this.container.append(this.builder); |
|
| 512 | 351 |
} |
| 513 |
- innerbq.append($('<span class="colon">: </span>'));
|
|
| 514 |
- newElem = this.build(json[i], innerbq, json, i, root); |
|
| 515 |
- if (newElem) if (newElem.text() == "??") elem = newElem; |
|
| 516 |
- bq.append(innerbq); |
|
| 517 |
- } |
|
| 352 |
+ this.saveScrollPosition(); |
|
| 353 |
+ this.builder.text('');
|
|
| 354 |
+ return this.showFunctionButtons("defined");
|
|
| 355 |
+ }; |
|
| 356 |
+ |
|
| 357 |
+ JSONEditor.prototype.updateStruct = function(struct, key, val, kind, selectionStart, selectionEnd) {
|
|
| 358 |
+ var orderrest; |
|
| 359 |
+ if (kind === 'key') {
|
|
| 360 |
+ if (selectionStart && selectionEnd) {
|
|
| 361 |
+ val = key.substring(0, selectionStart) + val + key.substring(selectionEnd, key.length); |
|
| 362 |
+ } |
|
| 363 |
+ struct[val] = struct[key]; |
|
| 364 |
+ orderrest = 0; |
|
| 365 |
+ $.each(struct, function(index, value) {
|
|
| 366 |
+ var tempval; |
|
| 367 |
+ if (orderrest & index !== val) {
|
|
| 368 |
+ tempval = struct[index]; |
|
| 369 |
+ delete struct[index]; |
|
| 370 |
+ struct[index] = tempval; |
|
| 371 |
+ } |
|
| 372 |
+ if (key === index) {
|
|
| 373 |
+ return orderrest = 1; |
|
| 374 |
+ } |
|
| 375 |
+ }); |
|
| 376 |
+ if (key !== val) {
|
|
| 377 |
+ return delete struct[key]; |
|
| 378 |
+ } |
|
| 379 |
+ } else {
|
|
| 380 |
+ if (selectionStart && selectionEnd) {
|
|
| 381 |
+ val = struct[key].substring(0, selectionStart) + val + struct[key].substring(selectionEnd, struct[key].length); |
|
| 382 |
+ } |
|
| 383 |
+ return struct[key] = val; |
|
| 384 |
+ } |
|
| 385 |
+ }; |
|
| 518 | 386 |
|
| 519 |
- bq.prepend(this.addUI(json)); |
|
| 520 |
- if (parent) {
|
|
| 521 |
- if (this._showWipe) bq.prepend(this.wipeUI(key, parent)); |
|
| 522 |
- bq.prepend(this.deleteUI(key, parent)); |
|
| 523 |
- } |
|
| 387 |
+ JSONEditor.prototype.getValFromStruct = function(struct, key, kind) {
|
|
| 388 |
+ if (kind === 'key') {
|
|
| 389 |
+ return key; |
|
| 390 |
+ } else {
|
|
| 391 |
+ return struct[key]; |
|
| 392 |
+ } |
|
| 393 |
+ }; |
|
| 524 | 394 |
|
| 525 |
- bq.append($('<div class="bracers">}</div>'));
|
|
| 526 |
- node.append(bq); |
|
| 527 |
- } else {
|
|
| 528 |
- elem = this.editable(json.toString(), key, parent, root, 'value').wrap('<span class="val"></span>').parent();
|
|
| 529 |
- node.append(elem); |
|
| 530 |
- node.prepend(this.braceUI(key, parent)); |
|
| 531 |
- node.prepend(this.bracketUI(key, parent)); |
|
| 532 |
- if (parent) {
|
|
| 533 |
- if (this._showWipe) node.prepend(this.wipeUI(key, parent)); |
|
| 534 |
- node.prepend(this.deleteUI(key, parent)); |
|
| 535 |
- } |
|
| 395 |
+ JSONEditor.prototype.doTruncation = function(trueOrFalse) {
|
|
| 396 |
+ if (this._doTruncation !== trueOrFalse) {
|
|
| 397 |
+ this._doTruncation = trueOrFalse; |
|
| 398 |
+ return this.rebuild(); |
|
| 399 |
+ } |
|
| 400 |
+ }; |
|
| 401 |
+ |
|
| 402 |
+ JSONEditor.prototype.showWipe = function(trueOrFalse) {
|
|
| 403 |
+ if (this._showWipe !== trueOrFalse) {
|
|
| 404 |
+ this._showWipe = trueOrFalse; |
|
| 405 |
+ return this.rebuild(); |
|
| 406 |
+ } |
|
| 407 |
+ }; |
|
| 408 |
+ |
|
| 409 |
+ JSONEditor.prototype.truncate = function(text, length) {
|
|
| 410 |
+ if (text.length === 0) {
|
|
| 411 |
+ return '-empty-'; |
|
| 412 |
+ } |
|
| 413 |
+ if (this._doTruncation && text.length > (length || 30)) {
|
|
| 414 |
+ return text.substring(0, length || 30) + '...'; |
|
| 415 |
+ } |
|
| 416 |
+ return text; |
|
| 417 |
+ }; |
|
| 418 |
+ |
|
| 419 |
+ JSONEditor.prototype.replaceLastSelectedFieldIfRecent = function(text) {
|
|
| 420 |
+ if (this.lastEditingUnfocusedTime > (new Date()).getTime() - 200) {
|
|
| 421 |
+ this.setLastEditingFocus(text); |
|
| 422 |
+ return this.rebuild(); |
|
| 423 |
+ } |
|
| 424 |
+ }; |
|
| 425 |
+ |
|
| 426 |
+ JSONEditor.prototype.editingUnfocused = function(elem, struct, key, root, kind) {
|
|
| 427 |
+ var selectionEnd, selectionStart, |
|
| 428 |
+ _this = this; |
|
| 429 |
+ selectionStart = elem != null ? elem.selectionStart : void 0; |
|
| 430 |
+ selectionEnd = elem != null ? elem.selectionEnd : void 0; |
|
| 431 |
+ this.setLastEditingFocus = function(text) {
|
|
| 432 |
+ _this.updateStruct(struct, key, text, kind, selectionStart, selectionEnd); |
|
| 433 |
+ return _this.json = root; |
|
| 434 |
+ }; |
|
| 435 |
+ return this.lastEditingUnfocusedTime = (new Date()).getTime(); |
|
| 436 |
+ }; |
|
| 437 |
+ |
|
| 438 |
+ JSONEditor.prototype.edit = function($elem, key, struct, root, kind) {
|
|
| 439 |
+ var $input, blurHandler, form, |
|
| 440 |
+ _this = this; |
|
| 441 |
+ form = $("<form></form>").css('display', 'inline');
|
|
| 442 |
+ $input = $("<input />");
|
|
| 443 |
+ $input.val(this.getValFromStruct(struct, key, kind)); |
|
| 444 |
+ $input.addClass('edit_field');
|
|
| 445 |
+ blurHandler = function() {
|
|
| 446 |
+ var val, _ref; |
|
| 447 |
+ val = $input.val(); |
|
| 448 |
+ _this.updateStruct(struct, key, val, kind); |
|
| 449 |
+ _this.editingUnfocused($elem, struct, (_ref = kind === 'key') != null ? _ref : {
|
|
| 450 |
+ val: key |
|
| 451 |
+ }, root, kind); |
|
| 452 |
+ $elem.text(_this.truncate(val)); |
|
| 453 |
+ $elem.get(0).editing = false; |
|
| 454 |
+ if (key !== val) {
|
|
| 455 |
+ return _this.rebuild(); |
|
| 456 |
+ } |
|
| 457 |
+ }; |
|
| 458 |
+ $input.blur(blurHandler); |
|
| 459 |
+ $input.keydown(function(e) {
|
|
| 460 |
+ if (e.keyCode === 9 || e.keyCode === 13) {
|
|
| 461 |
+ _this.doAutoFocus = true; |
|
| 462 |
+ return blurHandler(); |
|
| 463 |
+ } |
|
| 464 |
+ }); |
|
| 465 |
+ $(form).append($input).submit(function(e) {
|
|
| 466 |
+ e.preventDefault(); |
|
| 467 |
+ _this.doAutoFocus = true; |
|
| 468 |
+ return blurHandler(); |
|
| 469 |
+ }); |
|
| 470 |
+ $elem.html(form); |
|
| 471 |
+ return $input.focus(); |
|
| 472 |
+ }; |
|
| 473 |
+ |
|
| 474 |
+ JSONEditor.prototype.editable = function(text, key, struct, root, kind) {
|
|
| 475 |
+ var elem, self; |
|
| 476 |
+ self = this; |
|
| 477 |
+ elem = $('<span class="editable" href="#"></span>').text(this.truncate(text)).click(function(e) {
|
|
| 478 |
+ if (!this.editing) {
|
|
| 479 |
+ this.editing = true; |
|
| 480 |
+ self.edit($(this), key, struct, root, kind); |
|
| 481 |
+ } |
|
| 482 |
+ return true; |
|
| 483 |
+ }); |
|
| 484 |
+ return elem; |
|
| 485 |
+ }; |
|
| 486 |
+ |
|
| 487 |
+ JSONEditor.prototype.build = function(json, node, parent, key, root) {
|
|
| 488 |
+ var bq, elem, i, innerbq, jsonkey, jsonvalue, newElem, _i, _ref; |
|
| 489 |
+ elem = null; |
|
| 490 |
+ if (json instanceof Array) {
|
|
| 491 |
+ bq = $(document.createElement("BLOCKQUOTE"));
|
|
| 492 |
+ bq.append($('<div class="brackets">[</div>'));
|
|
| 493 |
+ bq.prepend(this.addUI(json)); |
|
| 494 |
+ if (parent) {
|
|
| 495 |
+ if (this._showWipe) {
|
|
| 496 |
+ bq.prepend(this.wipeUI(key, parent)); |
|
| 497 |
+ } |
|
| 498 |
+ bq.prepend(this.deleteUI(key, parent)); |
|
| 499 |
+ } |
|
| 500 |
+ for (i = _i = 0, _ref = json.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
|
| 501 |
+ innerbq = $(document.createElement("BLOCKQUOTE"));
|
|
| 502 |
+ newElem = this.build(json[i], innerbq, json, i, root); |
|
| 503 |
+ if (newElem && newElem.text() === "??") {
|
|
| 504 |
+ elem = newElem; |
|
| 505 |
+ } |
|
| 506 |
+ bq.append(innerbq); |
|
| 507 |
+ } |
|
| 508 |
+ bq.append($('<div class="brackets">]</div>'));
|
|
| 509 |
+ node.append(bq); |
|
| 510 |
+ } else if (json instanceof Object) {
|
|
| 511 |
+ bq = $(document.createElement("BLOCKQUOTE"));
|
|
| 512 |
+ bq.append($('<div class="bracers">{</div>'));
|
|
| 513 |
+ for (jsonkey in json) {
|
|
| 514 |
+ jsonvalue = json[jsonkey]; |
|
| 515 |
+ innerbq = $(document.createElement("BLOCKQUOTE"));
|
|
| 516 |
+ newElem = this.editable(jsonkey.toString(), jsonkey.toString(), json, root, 'key').wrap('<span class="key"></b>').parent();
|
|
| 517 |
+ innerbq.append(newElem); |
|
| 518 |
+ if (newElem && newElem.text() === "??") {
|
|
| 519 |
+ elem = newElem; |
|
| 520 |
+ } |
|
| 521 |
+ if (typeof jsonvalue !== 'string') {
|
|
| 522 |
+ innerbq.prepend(this.braceUI(jsonkey, json)); |
|
| 523 |
+ innerbq.prepend(this.bracketUI(jsonkey, json)); |
|
| 524 |
+ if (this._showWipe) {
|
|
| 525 |
+ innerbq.prepend(this.wipeUI(jsonkey, json)); |
|
| 526 |
+ } |
|
| 527 |
+ innerbq.prepend(this.deleteUI(jsonkey, json, true)); |
|
| 528 |
+ } |
|
| 529 |
+ innerbq.append($('<span class="colon">: </span>'));
|
|
| 530 |
+ newElem = this.build(jsonvalue, innerbq, json, jsonkey, root); |
|
| 531 |
+ if (newElem && newElem.text() === "??") {
|
|
| 532 |
+ elem = newElem; |
|
| 533 |
+ } |
|
| 534 |
+ bq.append(innerbq); |
|
| 535 |
+ } |
|
| 536 |
+ bq.prepend(this.addUI(json)); |
|
| 537 |
+ if (parent) {
|
|
| 538 |
+ if (this._showWipe) {
|
|
| 539 |
+ bq.prepend(this.wipeUI(key, parent)); |
|
| 540 |
+ } |
|
| 541 |
+ bq.prepend(this.deleteUI(key, parent)); |
|
| 542 |
+ } |
|
| 543 |
+ bq.append($('<div class="bracers">}</div>'));
|
|
| 544 |
+ node.append(bq); |
|
| 545 |
+ } else {
|
|
| 546 |
+ elem = this.editable(json.toString(), key, parent, root, 'value').wrap('<span class="val"></span>').parent();
|
|
| 547 |
+ node.append(elem); |
|
| 548 |
+ node.prepend(this.braceUI(key, parent)); |
|
| 549 |
+ node.prepend(this.bracketUI(key, parent)); |
|
| 550 |
+ if (parent) {
|
|
| 551 |
+ if (this._showWipe) {
|
|
| 552 |
+ node.prepend(this.wipeUI(key, parent)); |
|
| 553 |
+ } |
|
| 554 |
+ node.prepend(this.deleteUI(key, parent)); |
|
| 555 |
+ } |
|
| 556 |
+ } |
|
| 557 |
+ return elem; |
|
| 558 |
+ }; |
|
| 559 |
+ |
|
| 560 |
+ return JSONEditor; |
|
| 561 |
+ |
|
| 562 |
+ })(); |
|
| 536 | 563 |
|
| 537 |
- } |
|
| 538 |
- return elem; |
|
| 539 |
-}; |
|
| 564 |
+}).call(this); |
@@ -0,0 +1,37 @@ |
||
| 1 |
+.json-editor {
|
|
| 2 |
+ background-color: #FFF; |
|
| 3 |
+ position: relative; } |
|
| 4 |
+ .json-editor textarea {
|
|
| 5 |
+ width: 100%; |
|
| 6 |
+ font-family: monospace; } |
|
| 7 |
+ .json-editor .builder {
|
|
| 8 |
+ background-color: white; |
|
| 9 |
+ overflow: auto; |
|
| 10 |
+ font-size: 0.9em; } |
|
| 11 |
+ .json-editor .builder .key {
|
|
| 12 |
+ font-weight: bold; } |
|
| 13 |
+ .json-editor .builder .key .edit_field {
|
|
| 14 |
+ width: 150px; } |
|
| 15 |
+ .json-editor .builder .val .edit_field {
|
|
| 16 |
+ width: 200px; } |
|
| 17 |
+ .json-editor blockquote {
|
|
| 18 |
+ margin: 0; |
|
| 19 |
+ padding: 0; |
|
| 20 |
+ clear: both; |
|
| 21 |
+ padding-left: 7px; } |
|
| 22 |
+ .json-editor div {
|
|
| 23 |
+ background-color: #cfc; |
|
| 24 |
+ margin: 1px; |
|
| 25 |
+ padding: 2px; } |
|
| 26 |
+ .json-editor .val {
|
|
| 27 |
+ font-style: italic; } |
|
| 28 |
+ .json-editor .key a, .json-editor .val a {
|
|
| 29 |
+ color: black; |
|
| 30 |
+ text-decoration: none; } |
|
| 31 |
+ .json-editor .icon {
|
|
| 32 |
+ display: block; |
|
| 33 |
+ float: right; |
|
| 34 |
+ text-decoration: none; |
|
| 35 |
+ padding-left: 5px; |
|
| 36 |
+ border: 0; |
|
| 37 |
+ color: blue; } |
@@ -1,63 +0,0 @@ |
||
| 1 |
-.json-editor {
|
|
| 2 |
- background-color: #FFF; |
|
| 3 |
- position: relative; |
|
| 4 |
- |
|
| 5 |
- .builder {
|
|
| 6 |
- background-color: white; |
|
| 7 |
- overflow: auto; |
|
| 8 |
- font-size: 0.9em; |
|
| 9 |
- padding-right: 10px; |
|
| 10 |
- |
|
| 11 |
- .key {
|
|
| 12 |
- font-weight: bold; |
|
| 13 |
- |
|
| 14 |
- .edit_field {
|
|
| 15 |
- width: 80px; |
|
| 16 |
- } |
|
| 17 |
- |
|
| 18 |
- a {
|
|
| 19 |
- color: black; |
|
| 20 |
- text-decoration: none; |
|
| 21 |
- } |
|
| 22 |
- } |
|
| 23 |
- |
|
| 24 |
- .val {
|
|
| 25 |
- font-style: italic; |
|
| 26 |
- |
|
| 27 |
- .edit_field {
|
|
| 28 |
- width: 180px; |
|
| 29 |
- } |
|
| 30 |
- |
|
| 31 |
- a {
|
|
| 32 |
- color: black; |
|
| 33 |
- text-decoration: none; |
|
| 34 |
- } |
|
| 35 |
- } |
|
| 36 |
- } |
|
| 37 |
- |
|
| 38 |
- blockquote {
|
|
| 39 |
- margin: 0; |
|
| 40 |
- padding: 0; |
|
| 41 |
- clear: both; |
|
| 42 |
- padding-left: 7px; |
|
| 43 |
- } |
|
| 44 |
- |
|
| 45 |
- div {
|
|
| 46 |
- background-color: #cfc; |
|
| 47 |
- margin: 1px; |
|
| 48 |
- padding: 2px; |
|
| 49 |
- } |
|
| 50 |
- |
|
| 51 |
- .icon {
|
|
| 52 |
- display: block; |
|
| 53 |
- float: right; |
|
| 54 |
- text-decoration: none; |
|
| 55 |
- padding: 0 5px; |
|
| 56 |
- border: 0 !important; |
|
| 57 |
- color: blue; |
|
| 58 |
- |
|
| 59 |
- &:hover {
|
|
| 60 |
- background-color: #bbb; |
|
| 61 |
- } |
|
| 62 |
- } |
|
| 63 |
-} |